/*
  new Promise(function(resolve, reject) {
    // .....
  })
*/

/*
  一个 Promise有以下几种状态:
  pending: 初始状态，既不是成功，也不是失败状态。
  fulfilled: 意味着操作成功完成。
  rejected: 意味着操作失败。
*/
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
  // Promise构造函数执行时立即调用executor 函数
  constructor(excutor) {
   
    this.status = PENDING // 初始状态PENDING
    this.value = undefined // 传递成功方法的默认值
    this.reason = undefined // 传递失败原因的默认值
    this.successCallBack = [] // 成功的回调
    this.failCallBack = [] // 失败的回调

    try{
       // executor是带有 resolve 和 reject 两个参数的函数
      excutor(this.resolve, this.reject)
    } catch(e) {
      this.reject(e)
    }
  }

  resolve = (value) => {
    // promise状态只能由pending变为fulfilled或者rejected，一旦变为fulfilled或者rejected就无法改变为其他状态
    if(this.status !== PENDING) return
    // 执行成功回调
    while(this.successCallBack.length)  this.successCallBack.shift()()
    // 将状态置为fulfilled
    this.status = FULFILLED
    // 传递值
    this.value = value
  }

  reject = (reason) => {
    // 参考resolve即可
    if(this.status !== PENDING) return

    while(this.failCallBack.length) this.failCallBack.shift()()

    this.status = REJECTED

    this.reason = reason
  }

  //添加解决(fulfillment)和拒绝(rejection)回调到当前 promise, 返回一个新的 promise, 将以回调的返回值来resolve.
  then = (onFulfilled, onRejected) => {
    // then 会返回一个新的promise
    // onFulfilled, onRejected 均为可选参数
    onFulfilled = onFulfilled ? onFulfilled : value => value
    onRejected = onRejected ? onRejected : reason => { throw reason }

    var p = new MyPromise((resolve, reject) => {
      /* 根据不同状态执行不同方法, resolvePromise中需要传入这个新的promise对象，
      由于内部在同步执行的条件下无法获取这个promise对象，所以需要改成异步，此处用setTimeout实现*/
      if (this.status === FULFILLED) {
        try {
          setTimeout(() => {
            let res = onFulfilled(this.value)
  
            resolvePromise(p, res, resolve, reject)
          })
        } catch (e) {
          this.reject(e)
        }
      }

      if (this.status === REJECTED) {
        try{
          setTimeout(() => {
            let rej = onRejected(this.reason)
  
            resolvePromise(p, rej, resolve, reject)
          })
        } catch(e) {
          this.reject(e)
        }
      }

      // 异步操作的情况下，promise状态需要等待异步操作结果才会改变，所以在这种情况下需要先保存回调，等待异步操作有了结果以后触发回调
      if (this.status === PENDING) {
        this.successCallBack.push(() => {
          try {
            setTimeout(() => {
              let res = onFulfilled(this.value)
    
              resolvePromise(p, res, resolve, reject)
            })
          } catch (e) {
            this.reject(e)
          }
        })
        this.failCallBack.push(() => {
          try{
            setTimeout(() => {
              let rej = onRejected(this.reason)
    
              resolvePromise(p, rej, resolve, reject)
            })
          } catch(e) {
            this.reject(e)
          }
        })
      }
    })

    return p
  }

  catch = (onRejected) => {
    return this.then(undefined, onRejected)
  }

  finally = (callback) => {
    return this.then(value => {
      return MyPromise.resolve(callback()).then(() => value);
    }, reason => {
      return MyPromise.resolve(callback()).then(() => { throw reason })
    })
  }

  // promise的静态方法
  static resolve(value) {
    if (value instanceof MyPromise) return value;
    return new MyPromise(resolve => resolve(value));
  }

  static reject(value) {
    if (value instanceof MyPromise) return value;
    return new MyPromise(resolve, reject => reject(value));
  }

  static race(array) {
    return new MyPromise((resolve, reject) => {
      for(let i = 0; i < array.length; i++) {
        MyPromise.resolve(array[i]).then(res => {
          resolve(result)
        })
      }
    })
  }

  static all (array) {
    let result = []
    let index = 0
    return new MyPromise((resolve, reject) => {
      function addData (key, value) {
        result[key] = value
        index++
        if (index === array.length) {
          resolve(result)
        }
      }
      for (let i = 0; i < array.length; i++) {
        let current = array[i]
        if (current instanceof MyPromise) {
          // promise 对象
          current.then(value => addData(i, value), reason => reject(reason))
        }else {
          // 普通值
          addData(i, array[i])
        }
      }
    })
  }
}

function resolvePromise(p, val, resolve, reject) {
  // then如果返回了promise本身会产生调用死循环
  if (p === val) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }
  if (val instanceof MyPromise) {
    // promise 对象根据状态去执行对应的resolve，reject
    val.then(resolve, reject);
  } else {
    // 普通值
    resolve(val);
  }
}